#include"tcpsocket.hpp"
#include"cala.hpp"
#include<signal.h>

#define CHECK_RET(r) if((r) == false){return -1;}

void create_worker(Tcpsocket &sock){
    pid_t pid = fork();
    if(pid<0){
        sock.Close();
        return;
    }else if(pid == 0){
        while(1){
            std::string body;
            bool ret = sock.Recv(&body);
            if(ret == false){
                sock.Close();
                break;
            }
            std::cout<<"client say:"<<body<<std::endl;
            body.clear();
            std::cout<<"server say:";
            fflush(stdout);
            std::cin>>body;
            ret = sock.Send(body);
            if(ret == false){
                sock.Close();
                break;
            }
        }
        //子进程循环完毕就退出，不能让子进程继续运行
        sock.Close();
        exit(-1);
    }
    //父子进程数据独有，因此父进程关闭，并不影响子进程
    //并且父进程不关闭反而会造成资源泄露，因此父进程不与客户端通信

    sock.Close();
}
void *thread_entry(void *arg)
{
    Tcpsocket sock((long)arg);
    while(1){
        int fd = sock.Fd();
        cala_t tmp;
        recv(fd,&tmp,sizeof(cala_t),0);
        int result = -1;
        if(tmp._op == '+'){
            result = tmp._num1+tmp._num2;
        }
        send(fd,&result,sizeof(int),0);
    }
    sock.Close();
    return NULL;
}


void create_thread(Tcpsocket &sock)
{
    pthread_t tid;
    int ret = pthread_create(&tid,NULL,thread_entry,(void*)sock.Fd());
    if (ret!=0){
        std::cout<<"create thread error\n";
        sock.Close();
        return;
    }
    pthread_detach(tid);//分离线程，线程退出后自动释放资源，不需要被等待
}

int main(int argc,char* argv[])
{
    if(argc!=3){
        std::cout<<"usage:"<<"./tcp_srv 172.18.0.1 9000\n";
        return -1;
    }
    //显式忽略SIGCHLD信号处理，当子进程退出后，自动释放资源
    signal(SIGCHLD,SIG_IGN);
    std::string ip = argv[1];
    uint16_t port = std::stoi(argv[2]);
    Tcpsocket lsn_sock;
    //1.创建套接字
    CHECK_RET(lsn_sock.Socket());
    //2.绑定地址信息
    CHECK_RET(lsn_sock.Bind(ip,port));
    //3.开始监听
    CHECK_RET(lsn_sock.Listen());
    while(1){
        //4.获取新建连接
        Tcpsocket new_sock = lsn_sock.Accept();//这是一个阻塞接口
        if(new_sock.Available() == false){
            continue;
        }
        create_thread(new_sock);
    }
    //6.关闭套接字
    lsn_sock.Close();
    return 0;
}